import { RuntimeUtils } from './runtime-util';

export class ViewerInitializer {
    build;

    constructor() {
        this.build = new window.OBV.Api.ObvBuilder();
    }

    async loadViewModel({ applicationOptions, viewerModelItemList, viewerContainer, config3d }) {
        const build = this.build;
        const application = await this.buildApplication(applicationOptions);
        const obvDocumentModelList = await this.loadObvDocumentList(build, application, viewerModelItemList);
        const v3dModelList = this.getObvDocumentView3dList(obvDocumentModelList);
        const isLoad3d = v3dModelList && v3dModelList.length > 0;
        if (isLoad3d) {
            // 3d
            const obvApi = await build.buildViewer3d(application, viewerContainer, config3d);
            for (const item of v3dModelList) {
                await build.load3dModels(obvApi, item);
            }
            return { obvApi, application };
        }

        const v2dModel = this.getObvDocumentView2dItem(obvDocumentModelList);

        if (v2dModel && v2dModel.viewer2dItem) {
            const obvApi = await build.buildViewer2d(application, viewerContainer, config3d);
            this.listener2dError(obvApi);
            await build.load2dModels(obvApi, v2dModel);
            return { obvApi, application };
        }

        const vdocModelItem = this.getObvDocumentVdocItem(obvDocumentModelList);
        if (vdocModelItem && vdocModelItem.viewerDocItem) {
            // doc 只能加载一个
            const docApi = await build.buildViewerDoc(application, viewerContainer);
            build.loadDocModels(docApi, vdocModelItem.obvDocument, vdocModelItem.viewerDocItem);
            return { obvApi: docApi, application };
        }
    }

    listener2dError(obvApi) {
        obvApi.addEventListener(window.OBV.ViewerEventTypes.V2dError, (event) => {
            console.error(event);
            // '文件加载失败，请检查原始文件是否正确！',
        });
    }

    async buildApplication(applicationOptions) {
        try {
            if (!applicationOptions.refreshToken) {
                applicationOptions.refreshToken = applicationOptions.getAccessToken;
            }
            return this.build.buildApplication({ ...this._getApplicationOptions(), ...applicationOptions });
        } catch (e) {
            throw new Error('buildApplication error' + e);
        }
    }

    async loadDocument(application, urn) {
        try {
            return this.build.loadDocument(application, urn);
        } catch (e) {
            throw new Error('loadDocument error' + e);
        }
    }

    _getApplicationOptions() {
        return {
            serviceConfig: {
                origin: RuntimeUtils.instance.obvOrigin,
                apiContextPath: '/bimserver/viewing/v3',
            },
        };
    }

    getObvDocumentView3dList(obvDocumentModelList) {
        const list = [];
        for (const item of obvDocumentModelList) {
            if (item.obvDocument) {
                const v3dItems = item.obvDocument.getViewer3dItem(item.guid);
                v3dItems &&
                    list.push({
                        obvDocument: item.obvDocument,
                        viewer3dItem: v3dItems,
                        modelOffset: item.offset,
                    });
            }
        }
        return list;
    }

    getObvDocumentView2dItem(obvDocumentModelList) {
        let viewer2d;
        const obvDocumentModel = obvDocumentModelList.find((item) => {
            const v2dItem = item.obvDocument.getViewer2dItem(item.guid);
            if (v2dItem) {
                viewer2d = v2dItem;
                return true;
            }
        });
        if (obvDocumentModel) {
            return { obvDocument: obvDocumentModel.obvDocument, viewer2dItem: viewer2d };
        }
    }

    getObvDocumentVdocItem(obvDocumentModelList) {
        let vdoc;
        const obvDocumentModel = obvDocumentModelList.find((item) => {
            const vdocItem = item.obvDocument.getViewerDocItem(item.guid);
            if (vdocItem) {
                vdoc = vdocItem;
                return true;
            }
        });
        if (obvDocumentModel) {
            return { obvDocument: obvDocumentModel.obvDocument, viewerDocItem: vdoc };
        }
    }

    async loadObvDocumentList(build, application, viewerModelItemList) {
        const obvDocumentList = [];
        for (const item of viewerModelItemList) {
            const obvDocument = await build.loadDocument(application, item.documentUrn);
            obvDocumentList.push({ obvDocument, guid: item.guid, offset: item.offset });
        }
        return obvDocumentList;
    }
}
